package com.lcc.spring;

import javax.security.auth.login.Configuration;
import java.beans.Introspector;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <一句话功能描述> bean工厂
 * <功能详细描述>
 *
 * @author Mr Lcc
 * @version [版本号, 2024/11/23]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class LccApplicationContext {


    private Class configClass;

    /**
     * 存贮bean 描述
     */
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(16);

    /**
     * 存贮单例bean
     */
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    /**
     * 处理器
     */
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();


    public LccApplicationContext(Class configClass) {
        this.configClass = configClass;

        // 扫描bean
        doScan(configClass);

        // 初始化单例池
        beanDefinitionMap.forEach((key, beanDefinition) -> {
            if (beanDefinition.getScope().equals("singleton")) {
                Object bean = createBean(key, beanDefinition);
                singletonObjects.put(key, bean);
            }
        });
    }

    /**
     * <一句话功能描述> doScan
     * <功能详细描述>
     *
     * @param configClass 对象
     * @author Mr Lcc
     * @since 2024/11/23 22:16
     */
    private void doScan(Class configClass) {
        // 先获取所有实例对象 【非懒加载】
        if (configClass.isAnnotationPresent(ComponseScan.class)) {

            //获取注解
            ComponseScan componentScanAnnotation = (ComponseScan) configClass.getAnnotation(ComponseScan.class);
            String path = componentScanAnnotation.value();
            // com/zhouyu/service
            path = path.replace(".", "/");

            ClassLoader classLoader = LccApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);

            assert resource != null;
            File file = new File(resource.getFile());

            if (file.isDirectory()) {
                // target.class 文件反编译地址文件
                for (File f : file.listFiles()) {
                    String absolutePath = f.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\\", ".");

                    try {
                        //获取对象
                        Class<?> clazz = classLoader.loadClass(absolutePath);
                        if (clazz.isAnnotationPresent(Component.class)) {

                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
                                beanPostProcessorList.add(instance);
                            }

                            //获取bean名称
                            Component clazzAnnotation = clazz.getAnnotation(Component.class);
                            //bean 名称
                            String beanName = clazzAnnotation.value();
                            if ("".equals(beanName)) {
                                beanName = Introspector.decapitalize(clazz.getSimpleName());
                            }

                            // 需要容器储存bean信息
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(clazz);

                            // 判断是单例还是原型
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                String value = clazz.getAnnotation(Scope.class).value();
                                beanDefinition.setScope(value);
                            } else {
                                //默认
                                beanDefinition.setScope("singleton");
                            }

                            beanDefinitionMap.put(beanName, beanDefinition);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }

        }
    }

    /**
     * <一句话功能描述> 获取bean
     * <功能详细描述>
     *
     * @param beanName beanName
     * @return java.lang.Object
     * @author Mr Lcc
     * @since 2024/11/23 20:49
     */
    public Object getBean(String beanName) {

        if (!beanDefinitionMap.containsKey(beanName)) {
            throw new RuntimeException(beanName + "：不存在！");
        }

        //获取bean描述
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

        //判断是否单例 如果单例做一个map存贮，无需每次生成
        if (beanDefinition.getScope().equals("singleton")) {
            Object singletonBean = singletonObjects.get(beanName);
            if (singletonBean == null) {
                //创建bean
                singletonBean = createBean(beanName, beanDefinition);
            }
            return singletonBean;
        }
        // 原型
        Object prototypeBean = createBean(beanName, beanDefinition);
        return prototypeBean;
    }

    /**
     * <一句话功能描述> 创建bean
     * <功能详细描述>
     *
     * @param beanName       bean名称
     * @param beanDefinition bean定义
     * @return java.lang.Object
     * @author Mr Lcc
     * @since 2024/11/23 22:10
     */
    private Object createBean(String beanName, BeanDefinition beanDefinition) {

        Class clazz = beanDefinition.getType();
        Object instance = null;
        try {
            instance = clazz.getConstructor().newInstance();

            // Autowired 依赖注入赋值
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    field.set(instance, getBean(field.getName()));
                }
            }

            // 回调
            if (instance instanceof BeanNameAware) {
                ((BeanNameAware)instance).setBeanName(beanName);
            }

            //前置处理器
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
            }

            if (instance instanceof InitializingBean) {
                ((InitializingBean) instance).afterPropertiesSet();
            }

            //后置处理
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return instance;
    }

}
